package com.bestv.search.management.datasyn;

import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.*;
import com.bestv.search.common.model.uid.UID;
import com.bestv.search.common.util.StringConst;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SearchEngineSeriesSyncer extends ProgramSyncerImpl {
    public SearchEngineSeriesSyncer(Map<String, String> p) throws Exception {
        // Begin search engine series syncer
        this.setProps(p);
        justDoIt();
    }

    @Override
    public boolean init(Map<String, String> properties) {
        return initLastSyncTime(StringConst.BESTV_SEARCH_ENGINE, 1, StringConst.SEARCH_ENGINE_SERIES_SYNC_TIME);
    }

    @Override
    public boolean updateProgram() throws Exception {
        logger.info("Update search engine series @ " + new Date());
        thisSyncTime = lastSyncSuccessfullTime;

        String syncMessage = "Success sync engine series from search engine system @ " + new Date();
        try {
            // 获取最新搜索引擎需要优化的连续剧， 并对名称，OriginalSeriesNo做初步处理，同时生成相应的剧头
            Map<String, InfoHeaderDetail> infoHeaderDetailTable = new Hashtable<String, InfoHeaderDetail>();
            DataSourceKey dsKey = DataSourceKeyUtil.convert(systemCache.getLocalDataSourceKey());
            List<Program> newEngineSeries = pm.getNewEngineSeriesByUpdateTime(dsKey, lastSyncSuccessfullTime);
            for (Program info : newEngineSeries) {
                String nameFormat = "(.+)\\[([0-9]{1,})\\].*";
                Pattern pattern = Pattern.compile(nameFormat);
                Matcher matcher = pattern.matcher(info.getName());
                if (matcher.matches()) {
                    // Update last update time.
                    Date ut = info.getUpdateTime();
                    if (thisSyncTime == null || ut.after(thisSyncTime)) {
                        thisSyncTime = ut;
                    }

                    info.setUpdateFlag(1);
                    info.setUpdateTimeForIndex(new Date());
                    // 过滤连续剧名称，凡是以new或者new加数字结尾的, 均移除 new及以后的数字
                    String infoName = matcher.group(1);
                    String infoOrder = matcher.group(2);
                    String infoNameFormat = "(.+)new[0-9]{0,}";
                    Pattern infoNamePattern = Pattern.compile(infoNameFormat);
                    Matcher infoNameMatcher = infoNamePattern.matcher(infoName);
                    while (true) {
                        if (infoNameMatcher.matches()) {
                            infoName = infoNameMatcher.group(1);
                            infoNameMatcher = infoNamePattern.matcher(infoName);
                        } else {
                            break;
                        }
                    }

                    // Add series to infoHeaderDetail List
                    InfoHeaderDetail infoHeaderDetail = infoHeaderDetailTable.get(infoName);
                    if (infoHeaderDetail == null) {
                        infoHeaderDetail = new InfoHeaderDetail();
                        infoHeaderDetailTable.put(infoName, infoHeaderDetail);
                    }

                    // Generates info header
                    if (infoHeaderDetail.getInfoHeader() == null) {
                        // Don't exist header, get from DB or create a new one.
                        List<InfoHeader> infoHeader = infoHeaderManager.get(dsKey, infoName, info.getP_type());
                        InfoHeader infoHeaderInDB = null;
                        boolean isNew = false;
                        if (infoHeader == null || infoHeader.size() == 0) {
                            infoHeaderInDB = new InfoHeader();
                            isNew = true;
                        } else {
                            infoHeaderInDB = infoHeader.get(0);
                            isNew = false;
                        }

                        infoHeaderInDB.setName(infoName);
                        infoHeaderInDB.setCode(StringConst.SERIES
                                + StringConst.UNDERLINE
                                + systemCache.getLocalDataSourceKey()
                                + StringConst.UNDERLINE
                                + (info.getP_type() == null ? StringConst.EMPTY : String.valueOf(Math.abs(info
                                .getP_type().hashCode())) + String.valueOf(Math.abs(infoName.hashCode()))));
                        infoHeaderInDB.setGenre(info.getGenre());

                        Set<Tag> tags = info.getTags();
                        StringBuilder tagSb = new StringBuilder();
                        if (tags != null && tags.size() > 0) {
                            int i = 0;
                            for (Tag tag : tags) {
                                tagSb.append(tag.getTag());
                                i++;
                                if (i < tags.size()) {
                                    tagSb.append(StringConst.SPACE);
                                }
                            }
                            // 设置节目是否收费
                            if (tagSb.toString().contains("看大片") || tagSb.toString().contains("首映"))
                                infoHeaderInDB.setIsCharge(1);
                        }

                        infoHeaderInDB.setTags(tagSb.toString());
                        infoHeaderInDB.setStatus(1);
                        infoHeaderInDB.setActors(info.getActors());
                        infoHeaderInDB.setWriters(info.getDirectors());
                        infoHeaderInDB.setRegion(info.getRegion());
                        infoHeaderInDB.setReleased(info.getIssueYear());
                        infoHeaderInDB.setP_type(info.getP_type());
                        infoHeaderInDB.setBizType(info.getBizType());
                        infoHeaderInDB.setDescription(info.getDescription());
                        infoHeaderInDB.setLast_update_time(new Date());
                        infoHeaderInDB.setUpdate_time_for_index(new Date());
                        if (info.getHd() == 0) {
                            infoHeaderInDB.setClarity_flag(1);
                        } else if (info.getHd() == 1) {
                            infoHeaderInDB.setClarity_flag(2);
                        }

                        infoHeaderInDB.setLanguage(info.getLanguage());
                        infoHeaderInDB.setCategory(info.getCategory());

                        Set<Keyword> keywords = info.getKeywords();
                        StringBuilder keywordsSb = new StringBuilder();
                        if (keywords != null && keywords.size() > 0) {
                            int i = 0;
                            for (Keyword keyword : keywords) {
                                keywordsSb.append(keyword.getKeyword());
                                i++;
                                if (i < tags.size()) {
                                    keywordsSb.append(StringConst.SPACE);
                                }
                            }
                        }
                        infoHeaderInDB.setKeywords(keywordsSb.toString());
                        infoHeaderInDB.setHeaderType(StringConst.SERIES);

                        if (isNew) {
                            infoHeaderInDB.setId(new Long(UID.getUID(infoHeaderInDB)));
                        }

                        infoHeaderDetail.setInfoHeader(infoHeaderInDB);
                    }

                    InfoHeaderItem infoHeaderItem = new InfoHeaderItem();
                    infoHeaderItem.setInfo_header_id(infoHeaderDetail.getInfoHeader().getId());
                    infoHeaderItem.setInfo_id(info.getId());
                    infoHeaderItem.setOriginal_info_order(Integer.valueOf(infoOrder == null ? "0" : infoOrder));
                    infoHeaderItem.setUpdateTime(info.getUpdateTime());
                    infoHeaderDetail.getInfoDetail().add(infoHeaderItem);
                }
            }

            // 保存需要更新的info对象
            List<Info> infoList = new ArrayList<Info>();
            infoList.addAll(newEngineSeries);

            // 对新到节目与数据库中同类节目进行合并，排序
            for (String key : infoHeaderDetailTable.keySet()) {
                InfoHeaderDetail infoHeaderDetail = infoHeaderDetailTable.get(key);
                // 通过剧头id,获取该剧头的节目列表
                List<InfoHeaderItem> infoDetails = infoHeaderItemManager.getInfoHeaderItemByHeaderId(dsKey,
                        infoHeaderDetail.getInfoHeader().getId());
                List<Long> ids = new ArrayList<Long>();
                for (InfoHeaderItem infoHeaderItem : infoDetails) {
                    ids.add(infoHeaderItem.getInfo_id());
                }
                List<Info> infosInDB = vm.getInfoListByIds(dsKey, ids);

                // 通过剧头id,获取到节目
                if (infosInDB != null && infosInDB.size() > 0) {
                    // 如存在，将数据库中连续剧取出，合并至现有连续剧列表，以便排序, 更新
                    for (Info info : infosInDB) {
                        if (info.getUpdateFlag() == 2)
                            continue;
                        int index = getIndexById(infoList, info.getId());
                        if (index == -1) {
                            // 如果在将要保存的infoList中不存在，添加此info到将要保存的infoList中
                            info.setUpdateFlag(1);
                            info.setUpdateTimeForIndex(new Date());
                            infoList.add(info);
                        }

                        // 合并该节目头下已有的节目与新更新的节目
                        index = getIndexById(infoHeaderDetail.getInfoDetail(), info.getId());
                        if (index == -1) {
                            // 如果该节目在节目头中不存在，添加进节目详细列表
                            InfoHeaderItem infoHeaderItem = infoDetails.get(getIndexById(infoDetails, info.getId()));
                            infoHeaderDetail.getInfoDetail().add(infoHeaderItem);
                        }
                    }
                }

                // 按原有的剧集编号， 更新时间排序
                Collections.sort(infoHeaderDetail.getInfoDetail(), new Comparator<InfoHeaderItem>() {
                    @Override
                    public int compare(InfoHeaderItem info1, InfoHeaderItem info2) {
                        if (info1.getOriginal_info_order() - info2.getOriginal_info_order() > 0) {
                            return 1;
                        } else if (info1.getOriginal_info_order() - info2.getOriginal_info_order() < 0) {
                            return -1;
                        } else {
                            // 原有的剧集编号相等的时候，按第二字段排序
                            return info1.getUpdateTime().compareTo(info1.getUpdateTime());
                        }
                    }
                });

                // 更新连续剧剧集
                if (infoHeaderDetail.getInfoDetail().size() > 0) {
                    int minOriginalSeriesNo = infoHeaderDetail.getInfoDetail().get(0).getOriginal_info_order();
                    for (int i = 0; i < infoHeaderDetail.getInfoDetail().size(); i++) {
                        InfoHeaderItem infoHeader_item = infoHeaderDetail.getInfoDetail().get(i);
                        infoHeader_item.setInfo_order(infoHeader_item.getOriginal_info_order() - minOriginalSeriesNo
                                + 1);
                        // 如果同一集有多个vod，只保留最新的一个
                        if (i != infoHeaderDetail.getInfoDetail().size() - 1
                                && infoHeader_item.getOriginal_info_order() == infoHeaderDetail.getInfoDetail()
                                .get(i + 1).getOriginal_info_order()) {
                            for (Info info : infoList) {
                                if (info.getId() == infoHeader_item.getInfo_id()) {
                                    info.setUpdateFlag(2);
                                    info.setUpdateTimeForIndex(new Date());
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            List<InfoHeader> headers = new ArrayList<InfoHeader>();
            List<InfoHeaderItem> mappings = new ArrayList<InfoHeaderItem>();
            for (String key : infoHeaderDetailTable.keySet()) {
                headers.add(infoHeaderDetailTable.get(key).getInfoHeader());
                mappings.addAll(infoHeaderDetailTable.get(key).getInfoDetail());
            }

            infoHeaderManager.saveOrUpdate(dsKey, headers);

            int i = 0;
            for (Info info : infoList) {
                vm.saveUpdateInfo(dsKey, info);
                i++;
                if (i % 2000 == 0) {
                    Thread.sleep(2000);
                }
            }
            infoHeaderItemManager.saveOrUpdate(dsKey, mappings);

            // 处理节目已全部下线的剧头和有节目重新上线的剧头
            List<InfoHeader> offlineHeaders = new ArrayList<InfoHeader>();
            List<InfoHeader> allValidHeaders = infoHeaderManager.getAllValidHeader(dsKey);
            for (InfoHeader header : allValidHeaders) {
                // 通过节目头, 检查连续剧是否还在正常播放
                if (!infoHeaderManager.existOnlineInfosForHeaderId(dsKey, header.getId())) {
                    // Don't exist any related engine series, off line this
                    // series.
                    if (header.getStatus() == 1) {
                        header.setStatus(0);
                        header.setLast_update_time(new Date());
                        header.setUpdate_time_for_index(new Date());
                        offlineHeaders.add(header);
                    }
                }
            }

            infoHeaderManager.saveOrUpdate(dsKey, offlineHeaders);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e);
            syncMessage = "Failed sync engine series from search engine system @ " + new Date();
        } finally {

            // Update Sync status.
            updateSyncStatus(StringConst.BESTV_SEARCH_ENGINE, 1, StringConst.SEARCH_ENGINE_SERIES_SYNC_TIME,
                    syncMessage, thisSyncTime);
            logger.info("End update search engine series @ " + new Date());
        }

        return true;
    }

    private <T> int getIndexById(List<T> list, long infoId) {
        int index = 0;
        for (T t : list) {
            long id = 0;
            if (t instanceof Info) {
                id = ((Info) t).getId();
            } else if (t instanceof InfoHeaderItem) {
                id = ((InfoHeaderItem) t).getInfo_id();
            }

            if (id == infoId) {
                return index;
            }
            index++;
        }
        return -1;
    }

    private class InfoHeaderDetail {
        private InfoHeader infoHeader;

        private List<InfoHeaderItem> infoDetail = new ArrayList<InfoHeaderItem>();

        public List<InfoHeaderItem> getInfoDetail() {
            return infoDetail;
        }

        public InfoHeader getInfoHeader() {
            return infoHeader;
        }

        public void setInfoHeader(InfoHeader infoHeader) {
            this.infoHeader = infoHeader;
        }

    }
}